//
//  DynamicView.m
//  DynamicActionBlockDemo
//
//  Created by TOPTEAM on 2016/12/14.
//  Copyright © 2016年 TOPTEAM. All rights reserved.
//

#import "DynamicView.h"
@interface DynamicView()
#pragma mark-《UIDynamicBehavior的使用》
/*
 UIDynamicBehavior：仿真行为，是动力学行为的父类，
 
 UIDynamicAnimator
 可以通过该类添加不同的行为，来实现一些动态效果。
 
 基本的动力学行为类
 UIGravityBehavior（重力）、
 UICollisionBehavior（碰撞）、
 UIAttachmentBehavior（吸附）、
 UISnapBehavior（捕捉）、
 UIPushBehavior（推动）以及
 UIDynamicItemBehavior(辅助的行为UIDynamicItemBehavior，用来在item层级设定一些参数，比如item的摩擦，阻力，角阻力，弹性密度和可允许的旋转等等)
 均继承自该父类
 
 */
@property (strong,nonatomic) UIDynamicAnimator *dynamicAnimator;
@property (strong,nonatomic) UIGravityBehavior *gravityBehavior_up;
@property (strong,nonatomic) UIGravityBehavior *gravityBehavior_views;
@property (strong,nonatomic) CAShapeLayer *shapeLayer;
@property (strong,nonatomic) UIView *view_up;
@property (strong,nonatomic) UIImageView *ballImageView;


/*
 * 辅助视图
 */
@property (strong,nonatomic) UIView *view_middle;//中间的View
@property (strong,nonatomic) UIView *view_top;//上面的View
@property (strong,nonatomic) UIView *view_bottom;//下面的View

@end

@implementation DynamicView

-(id)initWithFrame:(CGRect)frame{
    self = [super initWithFrame:frame];
    if (self) {
        [self setUpViews];
    }
    return self;
}


-(void)setUpViews{
    
    _view_up=[[UIView alloc] initWithFrame:CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height/2)];
    [_view_up setAlpha:0.5];
    [self addSubview:_view_up];
    [_view_up.layer setShadowOffset:CGSizeMake(-1, 2)];
    [_view_up.layer setShadowOpacity:0.5];
    [_view_up.layer setShadowRadius:5.0];
    [_view_up.layer setShadowColor:[UIColor blackColor].CGColor];
    [_view_up.layer setMasksToBounds:NO];
    [_view_up.layer setShadowPath:[UIBezierPath bezierPathWithRect:_view_up.bounds].CGPath];
    
    UIPanGestureRecognizer *pan=[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(PanTheView:)];
    [_view_up addGestureRecognizer:pan];
    
    
    /*
     *  代码虽然多但就是简单的布局而已。
     唯一需要一提的就是 CAGradientLayer 。
     这是 <QuartzCore/CALayer.h> 中的一个类，
     估计平时接触的机会也比较少。
     
     其实这个类实现的渐变色效果非常有用，
     有了它你不再需要设计师提供的渐变色的切图了，
     一个常用的场景就是配图的文字背景。
     
     @property(copy) NSArray *colors;
     //定义需要显示的颜色，从上到下。
     @property(copy) NSArray *locations;
     //定义颜色的区间分布，
     比如三种颜色对应三个区间@[@(0.0),@(0.4),@(1.0)],
     注意必须实在 0~1 之间分布。默认是nil，会平均分布。
      
     @property CGPoint startPoint;
      
     @property CGPoint endPoint;
     //用来定义颜色渐变的方向。
     [0,0] 是左下角，[1,1] 是右上角。
     默认是[.5,0] 和 [.5,1]。
     
     */
    
    /*
     * 设置渐变 的背景色
     */
    CAGradientLayer *grd=[[CAGradientLayer alloc] init];
    [grd setFrame:_view_up.frame];
    grd.colors = [[NSArray alloc] initWithObjects:(__bridge id)([UIColor colorWithRed:0.0 green:191.0/255.0 blue:255.0/255.0 alpha:1].CGColor),(__bridge id)([UIColor whiteColor].CGColor), nil];
    [_view_up.layer addSublayer:grd];
    
    
    /*
     * 小球
     */
    _ballImageView=[[UIImageView alloc] initWithFrame:CGRectMake(
                                                                 (self.bounds.size.width/2)-30,
                                                                 self.bounds.size.height/1.5,
                                                                 60,
                                                                 60
                                                                 )
                    ];
    
    [_ballImageView setImage:[UIImage imageNamed:@"棒棒糖"]];
    [self addSubview:_ballImageView];
    [_ballImageView.layer setShadowOffset:CGSizeMake(-4, 4)];
    [_ballImageView.layer setShadowOpacity:0.5];
    [_ballImageView.layer setShadowRadius:5.0];
    [_ballImageView.layer setShadowColor:[UIColor blackColor].CGColor];
    [_ballImageView.layer setMasksToBounds:NO];
    
    //1
    _view_middle = [[UIView alloc] initWithFrame:CGRectMake(
                                                            _ballImageView.center.x-15,
                                                            200,
                                                            30,
                                                            30
                                                            )
                    ];
    [_view_middle setBackgroundColor:[UIColor orangeColor]];
    [self addSubview:_view_middle];
    //    [_view_middle setCenter:CGPointMake(
    //                                        _view_middle.center.x,
    //                                        (_ballImageView.center.y-_view_up.center.y)+15
    //                                        )
    [_view_middle setCenter:CGPointMake(
                                        _view_middle.center.x,
                                        self.bounds.size.height/2-15
                                        )
     ];
    
    //2
    _view_top = [[UIView alloc] initWithFrame:CGRectMake(
                                                         _ballImageView.center.x-15,
                                                         200,
                                                         30,
                                                         30
                                                         )
                 ];
    [_view_top setBackgroundColor:[UIColor redColor]];
    [self addSubview:_view_top];
    [_view_top setCenter:CGPointMake(
                                     _view_top.center.x,
                                     (_view_middle.center.y-_view_up.center.y) + _view_up.center.y/2
                                     )
     ];
    
    
    
    //3
    _view_bottom = [[UIView alloc] initWithFrame:CGRectMake(
                                                            _ballImageView.center.x-15,
                                                            200,
                                                            30,
                                                            30
                                                            )
                    ];
    [_view_bottom setBackgroundColor:[UIColor grayColor]];
    [self addSubview:_view_bottom];
    [_view_bottom setCenter:CGPointMake(
                                        _view_bottom.center.x,
                                        (_view_middle.center.y-_view_up.center.y)+_view_up.center.y*1.5
                                        )
     ];
    
    
    //将三个辅助点  隐藏掉
    _view_middle.hidden=YES;
    _view_top.hidden=YES;
    _view_bottom.hidden=YES;
    
    [self setUpBehaviors];
}

-(void)setUpBehaviors{
    
    
    _dynamicAnimator = [[UIDynamicAnimator alloc] initWithReferenceView:self];
    /*
     * 给最上方的矩形添加 UIGravityBehavior 和UICollisionBehavior
     */
    _gravityBehavior_up = [[UIGravityBehavior alloc] initWithItems:@[_view_up]];
    [_dynamicAnimator addBehavior:_gravityBehavior_up];
    
    //UICollisionBehavior
    UICollisionBehavior *Collision=[[UICollisionBehavior alloc] initWithItems:@[_view_up]];
    [Collision addBoundaryWithIdentifier:@"Left" fromPoint:CGPointMake(-1, 0) toPoint:CGPointMake(-1, [[UIScreen mainScreen] bounds].size.height)];
    [Collision addBoundaryWithIdentifier:@"Right" fromPoint:CGPointMake([[UIScreen mainScreen] bounds].size.width+1,0) toPoint:CGPointMake([[UIScreen mainScreen] bounds].size.width+1, [[UIScreen mainScreen] bounds].size.height)];
    [Collision addBoundaryWithIdentifier:@"Middle" fromPoint:CGPointMake(0, [[UIScreen mainScreen] bounds].size.height/2) toPoint:CGPointMake([[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height/2)];
    [_dynamicAnimator addBehavior:Collision];
    
    /*
     *
     在其下方添加三个UIAttachmentBehavior，分别连接着下方最近的对象。
     
     同时，我们把第一个灰块、第三个灰块以及小球这三个视图绑定到同一个
     UIGravityBehavior上面，叫做 gravityBehavior_views，在 gravityBehavior_views
     的 action block 中，把第一个灰块、第三个灰块作为一条贝塞尔曲线的
     两个控制点，实时地绘制出这条曲线，也就是你看到的「绳子」的样子了。
     
     */
    _gravityBehavior_views=[[UIGravityBehavior alloc] initWithItems:@[_ballImageView,_view_top,_view_bottom]];
    [_dynamicAnimator addBehavior:_gravityBehavior_views];
    
    __weak DynamicView *weakSelf = self;
    
    _gravityBehavior_views.action=^{
        NSLog(@"acting");
        UIBezierPath *path=[[UIBezierPath alloc] init];
        [path moveToPoint:weakSelf.view_up.center];
        [path addCurveToPoint:weakSelf.ballImageView.center controlPoint1:weakSelf.view_top.center controlPoint2:weakSelf.view_bottom.center];
        
        if (!weakSelf.shapeLayer) {
            weakSelf.shapeLayer = [[CAShapeLayer alloc] init];
            weakSelf.shapeLayer.fillColor = [UIColor clearColor].CGColor;
            weakSelf.shapeLayer.strokeColor = [UIColor colorWithRed:224.0/255.0 green:0.0/255.0 blue:35.0/255.0 alpha:1.0].CGColor;
            weakSelf.shapeLayer.lineWidth = 5.0;
            
            //Shadow
            [weakSelf.shapeLayer setShadowOffset:CGSizeMake(-1, 2)];
            [weakSelf.shapeLayer setShadowOpacity:0.5];
            [weakSelf.shapeLayer setShadowRadius:5.0];
            [weakSelf.shapeLayer setShadowColor:[UIColor blackColor].CGColor];
            [weakSelf.shapeLayer setMasksToBounds:NO];
            
            [weakSelf.layer insertSublayer:weakSelf.shapeLayer below:weakSelf.ballImageView.layer];
        }
        weakSelf.shapeLayer.path=path.CGPath;
    };
    
    
    
    // UIAttachmentBehaviors
    /*
     *   UIAttachmentBehavior
     实现一个效果让物体跟随手指移动
     */
    UIAttachmentBehavior *attach1=[[UIAttachmentBehavior alloc]initWithItem:_view_up attachedToItem:_view_top];
    [_dynamicAnimator addBehavior:attach1];
    
    UIAttachmentBehavior *attach2=[[UIAttachmentBehavior alloc] initWithItem:_view_top attachedToItem:_view_bottom];
    [_dynamicAnimator addBehavior:attach2];
    
    UIAttachmentBehavior *attach3=[[UIAttachmentBehavior alloc] initWithItem:_view_bottom offsetFromCenter:UIOffsetMake(0, 0) attachedToItem:_ballImageView offsetFromCenter:UIOffsetMake(0, -_ballImageView.bounds.size.height/2)];
    [_dynamicAnimator addBehavior:attach3];
    
    //UIDynamicItemBehavior
    UIDynamicItemBehavior *PanItem=[[UIDynamicItemBehavior alloc] initWithItems:@[_view_up,_view_top,_view_bottom,_ballImageView]];
    PanItem.elasticity = 0.5;
    /*
     * elasticity属性控制了物体的弹性。1.0代表完全弹性碰撞。也就是，碰撞过程中没有能量和速度损耗。这里设置elasticity的值为0.5，表示方块会在每次碰撞后速度都会减少。
     运行项目：
     
     在上面的代码中，只是改变了物体的弹性。而行为对象还有很多可以设置的属性：
     
     elasticity（弹性系数） – 决定了碰撞的弹性程度，比如碰撞时物体的弹性。
     friction（摩擦系数） – 决定了沿接触面滑动时的摩擦力大小。
     density（密度） – 跟 size 结合使用，来计算物体的总质量。质量越大，物体加速或减速就越困难。
     resistance（阻力） – 决定线性移动的阻力大小，这根摩擦系数不同，摩擦系数只作用于滑动运动。
     angularResistance（转动阻力） – 决定转动运动的阻力大小。
     allowsRotation（允许旋转） – 这个属性很有意思，它在真实的物理世界没有对应的模型。设置这个属性为 NO 物体就完全不会转动，无力受到多大的转动力。
     */
    [_dynamicAnimator addBehavior:PanItem];
    
}

-(void)PanTheView:(UIPanGestureRecognizer *)pan{
    
    CGPoint translation = [pan translationInView:pan.view];
    
    
    if (!(pan.view.center.y + translation.y>(self.bounds.size.height/2)-(pan.view.bounds.size.height/2))) {
        pan.view.center=CGPointMake(pan.view.center.x, pan.view.center.y+ translation.y);
        [pan setTranslation:CGPointMake(0, 0) inView:pan.view];
    }
    
    if (pan.state==UIGestureRecognizerStateBegan) {
        [_dynamicAnimator removeBehavior:_gravityBehavior_up];
    }
    else if (pan.state==UIGestureRecognizerStateChanged){
        
    }
    else if (pan.state==UIGestureRecognizerStateEnded) {
        [_dynamicAnimator addBehavior:_gravityBehavior_up];
    }
    
    
    /*
     * 接下来是必不可少的一行代码，
     在 _panView 的手势绑定方法中，
     我们需要实时调用这句：
     [_dynamicAnimator updateItemUsingCurrentState:pan.view];
      
      
     我们来看一下官方文档是怎么说的：
     // Update the item state in the animator if an external change was made to this item
     (void)updateItemUsingCurrentState:(id <UIDynamicItem>)item;
      
      
     Asks a dynamic animator to read the current state of a dynamic item, replacing the animator’s internal representation of the item’s state.A dynamic animator automatically reads the initial state (position and rotation) of each dynamic item you add to it, and then takes responsibility for updating the item’s state. If you actively change the state of a dynamic item after you’ve added it to a dynamic animator, call this method to ask the animator to read and incorporate the new state.
      
     文档中说，当外界变化（比如 _panGravity 开始作用了）
     作用于 pan.View 上时，去刷新当前_animator中所有
     item 的 position 和 rotation。
     
     而这些 item 包括着_ballImageView,
     _View_top,_View_bottom。
     
     position和rotation的变化又会触发_ballImageView,
     _View_top,_View_bottom 这三者绑定的_viewsGravity.action.
     在这个 action 中实时绘制一条贝塞尔曲线，就有了你看到的
     一条弹性的绳子。
     
     由于这个 action 会在动画的每一步都会调
     用（on every animation step，所以动画会显得相当流畅。
     
     
     */
    [_dynamicAnimator updateItemUsingCurrentState:pan.view];
    
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
    // Drawing code
}
*/

@end
